﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using System.Configuration;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using SocialLotus.DAO.Mappings.TestArea;
using System.Data.Common;
using System.Data.SqlClient;
using NHibernate.Dialect;
using SocialLotus.DAO;

namespace SocialLotus.DAO
{
    public class DAOFactory
    {
        /// <summary>
        /// Singleton that manages the NHibernate ISessionFactory and creates ISessions.
        /// </summary>
        private ISessionFactory _factory;

        #region Singleton

        private static readonly object _padlock = new object();
        private static DAOFactory _instance = null;

        private DAOFactory()
        {
            _factory = CreateSessionFactory();
        }

        /// <summary>
        /// Gets the singleton SessionFactory instance.
        /// </summary>
        /// <value>The instance.</value>
        public static DAOFactory Instance
        {
            get
            {
                lock (_padlock)
                {
                    if (_instance == null)
                    {
                        _instance = new DAOFactory();
                    }
                    //if (_newConnection)
                    //{
                    //    _instance = new DAOFactory();
                    //}

                    return _instance;
                }
            }
        }

        #endregion

        /// <summary>
        /// Gets a new NHibernate ISession.
        /// </summary>
        /// <returns></returns>
        internal ISession GetSession()
        {
            return _factory.OpenSession();
        }

        internal void RefreshConfiguration()
        {
            _factory = CreateSessionFactory();
        }


        /// <summary>
        /// Creates the NHibernate session factory.
        /// </summary>
        /// <returns></returns>
        private ISessionFactory CreateSessionFactory()
        {
            string defaultSchema = ConfigurationManager.AppSettings[DAOConstants.ConnectionConstants.DATABASE_SCHEMA];
            string connectionString = ConfigurationManager.ConnectionStrings[DAOConstants.ConnectionConstants.CONNECTION_CONFIGURATION_NAME].ConnectionString;

            if (defaultSchema == string.Empty)
            {
                throw new ArgumentOutOfRangeException("AppSetting for 'GeneralDatabasSchema' not set.");
            }

            FluentConfiguration fluentConfiguration = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                    .ShowSql()
                    .ConnectionString(c => c.Is(connectionString))
                .DefaultSchema(defaultSchema))
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<TestMaps>());

            return fluentConfiguration.BuildConfiguration().BuildSessionFactory();
        }

        public enum CreationType
        {
            DropAndCreate,
            Create,
            Update
        }

        public static bool CreateDatabaseSchema(CreationType creationType)
        {
            DbConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings[DAOConstants.ConnectionConstants.CONNECTION_CONFIGURATION_NAME].ConnectionString);

            try
            {
                try
                {
                    connection.Open();
                }
                catch
                {
                    connection.Close();
                    return false;
                }

                List<string> scripts = new List<string>();

                NHibernate.Cfg.Configuration configuration = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                    .ShowSql()
                    .Dialect<MsSql2008Dialect>()
                    .ConnectionString(c => c.Is(ConfigurationManager.ConnectionStrings[DAOConstants.ConnectionConstants.CONNECTION_CONFIGURATION_NAME].ConnectionString))
                .DefaultSchema(ConfigurationManager.AppSettings[DAOConstants.ConnectionConstants.DATABASE_SCHEMA]))
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<TestMaps>()).BuildConfiguration();

                if (creationType == CreationType.Create)
                {
                    foreach (string script in configuration.GenerateSchemaCreationScript(new NHibernate.Dialect.MsSql2008Dialect()))
                    {
                        scripts.Add(script);
                    }
                }
                else if (creationType == CreationType.DropAndCreate)
                {
                    foreach (string script in configuration.GenerateDropSchemaScript(new NHibernate.Dialect.MsSql2008Dialect()))
                    {
                        scripts.Add(script);
                    }
                    foreach (string script in configuration.GenerateSchemaCreationScript(new NHibernate.Dialect.MsSql2008Dialect()))
                    {
                        scripts.Add(script);
                    }
                }
                else
                {
                    foreach (string script in configuration.GenerateSchemaUpdateScript(new NHibernate.Dialect.MsSql2008Dialect(), new NHibernate.Tool.hbm2ddl.DatabaseMetadata(connection, new NHibernate.Dialect.MsSql2008Dialect())))
                    {
                        scripts.Add(script);
                    }
                }

                foreach (string command in scripts)
                {
                    DbCommand currentCommand = connection.CreateCommand();
                    currentCommand.CommandText = command;
                    currentCommand.ExecuteNonQuery();
                }

                connection.Close();

                return true;
            }
            catch (Exception ex)
            {
                ex.ToString();
                return false;
            }
            finally
            {
                connection.Close();
            }
        }
    
    }
}
